home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / recent / graburl.lha / GrabURL / rexx / GrabURL.rexx
OS/2 REXX Batch file  |  1997-01-18  |  23KB  |  694 lines

  1. /******************************************************************************
  2. *
  3. * $VER: GrabURL 1.02 (18.1.97) (c) 1996-97 Serge Emond
  4. *
  5. *******************************************************************************
  6. *
  7. * Url Types:
  8. *   F   Failed.
  9. *   Q   Queued
  10. *   R   Received
  11. *   X   Error.
  12. *   U   Unused/Unknown
  13. *
  14. ******************************************************************************/
  15.  
  16. options results
  17. options failat 100
  18. signal on break_c
  19. signal on halt
  20. signal on ioerr
  21.  
  22. PARSE ARG Arguments
  23. call Main
  24. call DoFail 0
  25.  
  26.  
  27. /********************************************************* Default Settings **/
  28.  
  29. DoDefaults:
  30.  
  31.   /* Boolean are always set by ReadArgs.. no defaults! */
  32.  
  33.   opts.Url.Count =      0                           /* Don't grab url */
  34.   opts.Depth =         -1                           /* Grab the world! */
  35.   opts.InFile =         ''                          /* Don't read files */
  36.   opts.MaxSize =        0                           /* No limit */
  37.   opts.MinSpaceLeft =   0                           /* No Checking */
  38.   opts.Pattern =        ''                          /* No Pattern Matching */
  39.   opts.SaveRoot =       'Work:Urls/'                /* Where to put files */
  40.   opts.WorkFile =       ''                          /* No WorkFile */
  41.   opts.Delay =          0   /* seconds */           /* Delay between grabs */
  42.   opts.MaxTime =        0   /* minutes */           /* Max. time to download */
  43.   opts.MaxCount =       0                           /* Max. # of file to grab */
  44.   opts.MaxBytes =       0                           /* Max. # of bytes to grab */
  45.  
  46.   /* Defaults not configurable on command-line */
  47.   
  48.   def.KeepReceived =    1   /* 1 = Keep Recd in list, 0 = Remove Them */
  49.   def.KeepFailed =      1   /* 1 = Keep Failed in list, 0 = Remove Them */
  50.   def.KeepUnused =      1   /* 1 = Keep Unused in list */
  51.   def.FollowMoved =     1   /* 1 = Grab new destination given by the server */
  52.   def.FollowTMoved =    1   /* 1 = Same as def.FollowMoved but when a */
  53.                             /* Temporary Move is issued */
  54.   def.Secure =          1   /* 1 = Save WorkFile each time it is modified */
  55.                             /* 0 = Save on exit only */
  56.   def.Accept =      '*/*'   /* We accept all types of files */
  57.   def.EMail =           ''  /* We are anonymous.. */
  58.   def.TimeZone =       300  /* Minutes to ADD to localtime to get GMT */
  59.   def.WriteBufSize = 16*1024 /* Write Buffer Size */
  60.   def.Translate = '~:[]()'  /* Characters to be translated to "_" when saving
  61.                                to disk */
  62.   def.TranslateTo = copies("_", length(def.Translate))
  63.                             /* Characters to translate to.. */
  64.  
  65.   def.TouchOldDirs =    1   /* 1 = Reset date of old directories */
  66.   
  67.   def.TempFile =    't:GrabURL.'UID /* Temporary file to use when parsing */
  68.  
  69.   def.ParsePattern = '(FTP|HTTP)://#?'  /* Just add ftp & http in the list */
  70.   
  71.   def.PasswordFile =    ''  /* File containing authentication infos */
  72.   
  73.   /* Where to find external programs */
  74.   def.Path       = ''
  75.   def.ScanHTML  = def.Path'ScanHTML'
  76.   def.GrabHTTP   = 'run <>nil: 'def.Path'GrabHTTP'
  77.   def.UrlManager = 'run <>nil: 'def.Path'UrlManager'
  78.   
  79.   /* Output information */
  80.   def.Output        = 'CONSOLE:'
  81.   def.Progress      = 1         /* 1 = Display progress in window */
  82.   def.ExitOnClose   = 0         /* 1 = Abort everything if CloseGadget
  83.                                    event.  0 = Skip current file  */
  84.  
  85.   /* Progress window font information */
  86.   def.Font          = 'topaz.font'
  87.   def.FSize         = 8
  88.  
  89.   /* ARexx Port Names */
  90.   um    = 'UM'UID
  91.   gh    = 'GH'UID
  92.   
  93. return 0
  94.  
  95. /**************************************************************** DoDefines **/
  96.  
  97. DoDefines:
  98.     UID = pragma('i')   /* Unique ID */
  99.     
  100.     if ~show('L', "rexxsupport.library") then
  101.         call AddLib("rexxsupport.library", 0, -30)
  102.     if ~show('L', "rexxdossupport.library") then
  103.         call AddLib("rexxdossupport.library", 0, -30, 0)
  104.     
  105.     opts = "Help/S,Url=U/M,Delay/N,Depth=D/N,HeaderOnly=HO/S,"
  106.     opts = opts"IfModified=IM/S,InFile=IF/K,MaxBytes=MB/N,MaxCount=MC/N,"
  107.     opts = opts"MaxSize=MS/N,MaxTime=MT/N,MinSpaceLeft=MSL/N,"
  108.     opts = opts"NoBG/S,NoDirs=ND/S,NoHRef/S,NoSrc/S,NotExists=NE/S,"
  109.     opts = opts"Pattern=P/K,Query=Q/S,Recursive=R/S,Retry/S,"
  110.     opts = opts"SaveHeaders=SH/S,SaveRoot=SR/K,Verbose/S,WorkFile=WF/K"
  111.     
  112.     LF = '0a'x
  113.     
  114. return 0
  115.  
  116. /** Main *********************************************************************/
  117.  
  118. Main:
  119.     call DoDefines
  120.     call DoDefaults
  121.     
  122.     if ~open('l', def.Output, 'W') then do
  123.         say 'Can''t open output display'
  124.         exit(10)
  125.     end
  126.  
  127.     if Arguments = '?' then do
  128.         call Log(opts)
  129.         call DoFail 0
  130.     end
  131.  
  132.     if strip(Arguments) = '' then do
  133.         call Log("Nothing to do!")
  134.         call DoFail 10
  135.     end
  136.  
  137.     if ~ReadArgs(Arguments, opts, "opts.") then
  138.         call DoFail(10, 'Error: 'Fault(RC))
  139.     
  140.     if opts.Help then call DisplayHelp
  141.     
  142.     /* Do we have something to do? */
  143.     if (opts.Url.Count = 0) & (opts.InFile = '') & (opts.WorkFile = '') then
  144.         DoFail 0
  145.     
  146.     call DoInit
  147.     call ReadRealms
  148.  
  149.     /* ScanHTML really likes stack.. */
  150.     oldstack = pragma('s',16384)
  151.     if oldstack>16384 then call pragma('s',oldstack)
  152.     drop oldstack
  153.  
  154.     call OpenPorts
  155.     
  156.     call AddUrls
  157.         
  158.     call cmd(um, 'GetInMem')
  159.     
  160.     if opts.Verbose then call Log umres' urls to process'
  161.     
  162.     call TheLoop
  163.     
  164.     if ~def.KeepReceived then call cmd(um, 'KillType R')
  165.     if ~def.KeepFailed then call cmd(um, 'KillType F')
  166.     call SaveWorkFile
  167.     
  168. call DoFail 0
  169.  
  170. /** Log **********************************************************************/
  171.  
  172. Log:
  173.     PARSE ARG log_text, log_nolf
  174.     
  175.     if log_nolf=1 then call writech('l', log_text)
  176.     else call writeln('l', log_text)
  177.     
  178.     drop log_text log_nolf
  179. return 0
  180.  
  181. /** DoFail********************************************************************/
  182. break_c:
  183.     say '***BREAK'
  184.     call DoFail 10
  185. DoFail:
  186.     PARSE ARG fail.rc, fail.msg
  187.     
  188.     if fail.rc = '' then fail.rc = 0
  189.     if text_message~='' & fail.rc~=0 then call Log(fail.msg)
  190.     
  191.     if show('P', gh) then call cmd(gh, 'Quit')
  192.     if show('P', um) then call cmd(um, 'Quit')
  193.     
  194.     call close('l')
  195.     
  196. exit fail.rc
  197.  
  198. /** Display Help *************************************************************/
  199.  
  200. DisplayHelp:
  201.     call Log "Arguments (Abbrev) <arg>"
  202.     call Log "    <#> -> number"
  203.     call Log "    <s> -> string"
  204.     call Log
  205.     call Log " URL (U) <s>         Url to grab (can have multiple arguments)"
  206.     call Log " InFile (IF) <s>     Input file containing one url/line to grab"
  207.     call Log " WorkFile (WF) <s>   File to load/save urls to.  (Keeping flags)"
  208.     call Log ""
  209.     call Log " Depth (D) <#>       Level of recursion (Default: grab indefinitely)"
  210.     call Log " IfModified (IM)     Grab only files modified since last grab"
  211.     call Log " MaxCount (MC) <#>   Maximal number of file to grab"
  212.     call Log " MaxSize (MS) <#>    Maximal size a file can have in order to grab it"
  213.     call Log " MaxTime (MT) <#>    Maximal time to download in minutes"
  214.     call Log " MinSpaceLeft (MSL) <#>  Minimal space to leave on disk when grabbing"
  215.     call Log " NoBG                Don't get background images"
  216.     call Log " NoHRef              Don't get referenced files"
  217.     call Log " NoSrc               Don't get 'SRC' urls"
  218.     call Log " NotExists (NE)      Grab only if the file does not already exists on disk"
  219.     call Log " Pattern (P) <s>     AmigaDOS pattern telling which URLs to grab"
  220.     call Log " Query (Q)           Allow '?' in urls"
  221.     call Log " Recursive (R)       Collect files recursively"
  222.     call Log " Retry               Retry files that failed"
  223.     call Log ""
  224.     call Log " Delay <#>           Time to wait between each grab (seconds)"
  225.     call Log " HeaderOnly (HO)     Grab headers, not the files"
  226.     call Log " NoDir (ND)          Don't create dirs - put the file in current directory"
  227.     call Log " SaveHeaders (SH)    Save the header of each file (.HDR)"
  228.     call Log " SaveRoot (SR) <s>   Directory where to put files"
  229.     call Log " Verbose             Display more stuff"
  230.     call Log ""
  231.     call Log "Please see docs for more infos."
  232.     call DoFail 0
  233.  
  234. /** cmd **********************************************************************/
  235.  
  236. /* Send a string to an ARexx port */
  237.  
  238. cmd:
  239.     PARSE ARG port, commd
  240.     
  241.     address value port
  242.     
  243.     commd
  244.     
  245.     drop port string
  246. return RC
  247.  
  248. /** DoInit - Initialize Vars *************************************************/
  249.  
  250. DoInit:
  251.     g.cnt = 0                       /* # of url we are grabbing */
  252.     g.bytes = 0                     /* # of bytes we received */
  253.     opts.TDelay = 50 * opts.Delay   /* Transform in ticks */
  254.     opts.MaxTimeS = opts.MaxTime*60 /* Transform in seconds */
  255.     call time('r')                  /* Reset the time to 0 */
  256. return 0
  257.  
  258. /** OpenPorts ****************************************************************/
  259.  
  260. OpenPorts:
  261.     
  262.     /* Port already in use...? */
  263.     if show('P', gh) then call DoFail(10, 'Port already in use')
  264.     /* Port already in use...? */
  265.     if show('P', um) then call DoFail(10, 'Port already in use')
  266.  
  267.     /* Start GrabHTTP */
  268.     OP.cmd = def.GrabHTTP' PORT 'gh' ACCEPT 'def.Accept' Font 'def.Font' FontSize 'def.FSize' WBuf 'def.WriteBufSize
  269.     address command OP.cmd
  270.     if RC ~= 0 then call DoFail(10, 'Can''t start GrabHTTP')
  271.     
  272.     OP.i=0; do forever
  273.         if show('P', gh) then break
  274.         OP.i = OP.i + 1
  275.         if OP.i = 10 then call DoFail(10, 'Can''t find GrabHTTP''s port')
  276.         call Delay(20)      /* Wait 0.2 secs (10*20/50) */
  277.     end
  278.     
  279.     /* Add '/' to SaveRoot path */
  280.     OP.test = opts.SaveRoot ~= ''
  281.     OP.test = OP.test & right(opts.SaveRoot,1) ~= ':'
  282.     OP.test = OP.test & right(opts.SaveRoot,1) ~= '/'
  283.     if OP.test then opts.SaveRoot = opts.SaveRoot'/'
  284.     drop OP.test
  285.         
  286.     /* CD to SaveRoot dir */
  287.     if cmd(gh, 'SetDir "'opts.SaveRoot'"') ~= 0 then
  288.         call DoFail(10, 'Error cd saveroot directory')
  289.     
  290.     /* Set other defaults */
  291.     call cmd(gh, 'SetMinSpaceLeft 'opts.MinSPaceLeft)
  292.     call cmd(gh, 'SetEMail 'def.EMail)
  293.     if cmd(gh, 'SetTimeZone m 'def.TimeZone) ~= 0 then
  294.         call DoFail(10, 'Error setting TimeZone')
  295.     
  296.     /* Start UrlManager */
  297.     OP.cmd = def.UrlManager || ' PORT ' || um
  298.     address command OP.cmd
  299.     if RC ~= 0 then call DoFail(10, 'Can''t start UrlManager')
  300.     
  301.     OP.i=0; do forever
  302.         if show('P', um) then break
  303.         OP.i = OP.i + 1
  304.         if OP.i = 10 then call DoFail(10, 'Can''t find UrlManager''s port')
  305.         call Delay(20)      /* Wait 0.2 secs (10*20/50) */
  306.     end
  307.     
  308.     drop OP.i OP.cmd
  309. return 0
  310.  
  311. /** AddUrls ******************************************************************/
  312.  
  313. /* Priority: CLI urls prevails on InFile, InFile on WorkFile */
  314.  
  315. AddUrls:
  316.     /* Add Urls */
  317.     if opts.Url.count ~= 0 then do i = 0 to opts.Url.count-1
  318.         
  319.         /* Simple HTTP:// checking */
  320.         if left(upper(opts.Url.i),7) ~= 'HTTP://' then iterate
  321.         
  322.         thecmd = 'AddUrl TYPE Q URL "'opts.Url.i'" DEPTH '
  323.         if opts.Recursive then thecmd = thecmd || opts.Depth
  324.         else thecmd = thecmd || '0'
  325.         
  326.         if cmd(um, thecmd) = 2 then call DoFail(10, "Error adding url")
  327.     end
  328.     drop i
  329.     
  330.     /* Add InFile */
  331.     if opts.InFile ~='' then do
  332.         thecmd = 'ReadFile FILE "'opts.InFile'" TYPE Q DEPTH '
  333.         if opts.Recursive then thecmd = thecmd || opts.Depth
  334.         else thecmd = thecmd || '0'
  335.         
  336.         if cmd(um, thecmd) ~= 0 then call DoFail(10, "Error adding InFile")
  337.     end
  338.     drop thecmd
  339.     
  340.     /* Get WorkFile */
  341.     if (opts.WorkFile ~= '') & exists(opts.WorkFile) then
  342.         call cmd(um, 'LoadFile "'opts.WorkFile'"')
  343. return 0
  344.  
  345. /** SaveWorkFile *************************************************************/
  346.  
  347. SecureWorkFile:
  348.  
  349.     /* Don't save if not secure */
  350.     if ~def.Secure then return 0
  351.  
  352. SaveWorkFile:
  353.  
  354.     /* Don't save if no workfile! 8) */
  355.     if opts.WorkFile = '' then return 0
  356.     
  357.     if cmd(um, 'SaveFile FILE "'opts.WorkFile'" FULL') ~= 0 then
  358.         call DoFail(10, "Error: Can't save workfile!?")
  359. return 0
  360.  
  361. /** Realm Stuff **************************************************************/
  362.  
  363. ReadRealms:
  364.     if def.PasswordFile='' then do
  365.         authtot=0
  366.         return 0
  367.     end
  368.     if ~open('r',def.PasswordFile,'r') then
  369.         call DoFail(20, 'Error openning password file')
  370.     rri=0
  371.     do while ~eof('r')
  372.         line = readln('r')
  373.         if line='' then iterate
  374.         if left(line,1)=';' then iterate
  375.         rri=rri+1
  376.         parse var line authr.rri':'authu.rri
  377.     end
  378.     authtot = rri
  379.     drop rri
  380. return 0
  381.  
  382. GetRealm:
  383.     PARSE ARG gr.rlm
  384.     do gri=1 to authtot
  385.         if gr.rlm = authr.gri then return authu.gri
  386.     end
  387. return ''
  388.  
  389. /** TheLoop ******************************************************************/
  390.  
  391. TheLoop:
  392.     call TheLoop2 'Q'
  393.     if opts.Retry then
  394.         call TheLoop2 'F'
  395. return 0
  396.  
  397. TheLoop2:
  398. parse arg tl.type
  399.     /* First we do 'Q'ueued urls */
  400.     j = 1; gu.lmoved = 0
  401.     do forever
  402.         if gu.lmoved = 0 then do
  403.             call cmd(um, 'Search 'j' type 'tl.type' pattern "HTTP://#?"')
  404.             i = umres
  405.  
  406.             if i=0 then break       /* No more url */
  407.  
  408.             g.cnt = g.cnt+1
  409.             j = i+1
  410.  
  411.             if g.cnt > 1 then call Delay(opts.TDelay)
  412.         end
  413.         if i=0 then break
  414.  
  415.         gu.lmoved = 0
  416.         call GetUrl(i)
  417.         if gu.lmoved = 1 then do
  418.             call cmd(gh, 'GetHeaderString "Location:"')
  419.             if upper(left(ghres, 9)) = 'LOCATION:' then do
  420.                 newurl = strip(right(ghres, length(ghres)-10))
  421.                 call cmd(um, 'SetUrl ID 'i' URL "'newurl'"')
  422.                 drop newurl
  423.             end
  424.             else do
  425.                 gu.lmoved = 0
  426.             end
  427.         end
  428.         else do
  429.             if ((opts.MaxCount ~= 0 ) & (g.cnt >= opts.MaxCount)) then do
  430.                 call Log 'Received the maximal number of file allowed'
  431.                 return 0
  432.             end
  433.             tl.el = time('e')
  434.             if ((opts.MaxTime ~= 0) & (opts.MaxTimeS <= time('e'))) then do
  435.                 tl.el = tl.el/60
  436.                 call Log 'Downloaded 'tl.el' mins, max was 'opts.MaxTime' mins'
  437.                 return 0
  438.             end
  439.             call cmd(gh, 'GetByteRecd')
  440.             g.bytes = g.bytes + ghres
  441.             if (opts.MaxBytes ~= 0) & (g.bytes >= opts.MaxBytes) then do
  442.                 call Log 'Downloaded 'g.bytes' bytes, max was 'opts.MaxBytes' bytes'
  443.                 return 0
  444.             end
  445.         end
  446.     end
  447.  
  448. return 0
  449.  
  450. /** GetUrl *******************************************************************/
  451.  
  452. GetUrl:
  453.     PARSE ARG gu.id, gu.isfailed
  454.     
  455.     if cmd(um, 'GetURL 'gu.id) ~= 0 then return 0
  456.     gu.url = umres
  457.     if cmd(um, 'GetDepth 'gu.id) ~= 0 then return 0
  458.     gu.depth = umres
  459.     
  460.     gu.out = '['right(g.cnt, 4)'] 'gu.url
  461.     if gu.isfailed ~= '' then gu.out = gu.out' (F)'
  462.     if opts.Recursive then gu.out = gu.out' (D: 'gu.depth')'
  463.     
  464.     call Log(gu.out'...', 1)
  465.     
  466.     if upper(left(gu.url,7)) ~= "HTTP://" then do
  467.         call Log ' Not HTTP'
  468.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  469.         else call cmd(um, 'KillUrl 'hu.id)
  470.         if def.Secure then call SecureWorkFile
  471.         return 0
  472.     end
  473.     
  474.     /* Separate host & path */
  475.     parse var gu.url shit '://' gu.hp '/' gu.path
  476.  
  477.     if gu.hp = '' then do
  478.         call Log ' Not grabbed'
  479.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  480.         else call cmd(um, 'KillUrl 'hu.id)
  481.         if def.Secure then call SecureWorkFile
  482.         return 0
  483.     end
  484.     
  485.     /* Separate host & port */
  486.     parse var gu.hp gu.host ':' gu.port
  487.     
  488.     if gu.host = '' then do
  489.         call Log ' Not grabbed'
  490.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  491.         else call cmd(um, 'KillUrl 'hu.id)
  492.         if def.Secure then call SecureWorkFile
  493.         return 0
  494.     end
  495.     if gu.port = '' then gu.port = 80
  496.     
  497.     /* Complete the name */
  498.     if gu.path = '' then gu.path = 'index.html'
  499.     else if right(gu.path, 1) = '/' then gu.path = gu.path || 'index.html'
  500.     
  501.     /* Strip path if nodirs */
  502.     if opts.NoDirs then do while index(gu.path, '/') ~= 0
  503.         gu.path = right(gu.path, length(gu.path) - index(gu.path, '/'))
  504.     end
  505.     else gu.path = gu.host'/'gu.path
  506.  
  507.     /* Translates the filename */
  508.     if def.Translate ~= '' then do
  509.         call cmd(gh, 'Translate "'gu.path'" "'def.Translate'" "'def.TranslateTo'"')
  510.         gu.path = GHRES
  511.     end
  512.  
  513.     /* Check if it already exists */
  514.     if opts.NotExists & Exists(opts.SaveRoot||gu.path) then do
  515.         call Log ' Already on disk'
  516.         if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  517.         else call cmd(um, 'KillUrl 'hu.id)
  518.         if def.Secure then call SecureWorkFile
  519.         return 0
  520.     end
  521.  
  522.     thecmd = 'GetHTTPFile "'gu.url'"'
  523.     if def.Progress then thecmd = thecmd' Progress'
  524.     if ~opts.NoDirs then thecmd = thecmd' FileName "'gu.path'"'
  525.     if opts.MaxSize ~= 0 then thecmd = thecmd' MaxSize 'opts.MaxSize
  526.     if opts.SaveHeaders then thecmd = thecmd' SaveHeader'
  527.     if opts.IfModified then thecmd = thecmd' IfModified'
  528.     if opts.HeaderOnly then thecmd = thecmd' HeaderOnly'
  529.     if def.TouchOldDirs then thecmd = thecmd' TouchDirs'
  530.  
  531.     call cmd(gh, thecmd)
  532.     gu.res = ghres
  533.  
  534.     /* Authorization Check */
  535.     if gu.res = '100' then do
  536.         call cmd(gh, 'GetHeaderString "HTTP/1."')
  537.         parse var ghres dummy" "h.code" "h.msg
  538.         if h.code = '401' then do
  539.             call Log(' [Auth]', 1)
  540.             call cmd(gh, 'GetHeaderString "WWW-Authenticate: Basic "')
  541.             if RC=0 then do
  542.                 parse var ghres dummy '"'g.realm'"'
  543.                 g.authpwd = GetRealm(g.realm)
  544.                 if g.authpwd = '' then do
  545.                     call Log(' Unknown realm: "'g.realm'"', 1)
  546.                     gu.res = 9999
  547.                 end
  548.                 else do
  549.                     call cmd(gh, 'SetAuth "'g.authpwd'"')
  550.                     if RC~=0 then call DoFail(20, "Error: can't alloc mem for authentication!")
  551.                     call cmd(gh, thecmd)
  552.                     gu.res = ghres
  553.                     call cmd(gh, 'SetAuth')
  554.                 end
  555.             end
  556.             else do
  557.                 call Log(' Unknown authentication method!')
  558.                 gh.res = 9999
  559.             end
  560.         end
  561.     end
  562.  
  563.     if gu.res = '0' then do
  564.         if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  565.         else call cmd(um, 'KillUrl 'hu.id)
  566.         call Log(' Done.', 1)
  567.         end
  568.     else if gu.res = '200' then do
  569.         call cmd(um, 'SetType 'gu.id' F')
  570.         call Log(' Incomplete file.', 1)
  571.     end
  572.     else if gu.res = '9999' then nop
  573.     else if gu.res = '100' then do
  574.         call cmd(gh, 'GetHeaderString "HTTP/1."')
  575.         parse var ghres dummy" "h.code" "h.msg
  576.         if h.code = '304' then do
  577.             call Log(' Not modified.', 1)
  578.             if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  579.             else call cmd(um, 'KillUrl 'hu.id)
  580.             end
  581.         else if h.code = '301' then do
  582.             call Log(' Moved.', 1)
  583.             if def.FollowMoved = '1' then gu.lmoved = 1
  584.             else if def.FollowMoved = 'F' then call cmd(um, 'SetType 'gu.id' F')
  585.             else if def.FollowMoved = 'X' then call cmd(um, 'SetType 'gu.id' X')
  586.             end
  587.         else if h.code = '302' then do
  588.             call Log(' Moved temporarily.', 1)
  589. /*            if def.KeepReceived then call cmd(um, 'SetType 'gu.id' F') */
  590. /*            else call cmd(um, 'KillUrl 'hu.id) */
  591.             if def.FollowTMoved = '1' then gu.lmoved = 1
  592.             else if def.FollowTMoved = 'F' then call cmd(um, 'SetType 'gu.id' F')
  593.             else if def.FollowTMoved = 'X' then call cmd(um, 'SetType 'gu.id' X')
  594.             end
  595.         else if h.code = '401' then do
  596.             call Log(' Bad user/password.', 1)
  597.             call cmd(um, 'SetType 'gu.id' U')
  598.             end
  599.         else do
  600.             call Log(' 'h.code' 'h.msg'.', 1)
  601.             if def.KeepReceived then call cmd(um, 'SetType 'gu.id' X')
  602.             else call cmd(um, 'KillUrl 'hu.id)
  603.             end
  604.         end
  605.     else if gu.res='104' then do
  606.         call Log(' Host not found.', 1)
  607.         call cmd(um, 'SetType 'gu.id' X')
  608.     end
  609.     else if gu.res='107' then do
  610.         call Log(' Disk Full.', 1)
  611.         call DoFail(20, "Error Disk Full.")
  612.     end
  613.     else if gu.res='200' then do
  614.         call Log(' File incomplete.', 1)
  615.         call cmd(um, 'SetType 'gu.id' F')
  616.     end
  617.     else if gu.res='201' then do
  618.         call Log(' User Abort.', 1)
  619.         if ~def.ExitOnClose then call cmd(um, 'SetType 'gu.id' F')
  620.         else call DoFail(10, "Error: User abort.")
  621.     end
  622.     else if gu.res='97' then do
  623.         call Log(' Failed to create socket.', 1)
  624.         call DoFail(20, "Error.")
  625.     end
  626.     else if (gu.res='98') | (gu.res='99') | (gu.res='164') then do
  627.         call Log(' Not enough memory.', 1)
  628.         call DoFail(20, "Error.")
  629.     end
  630.     else do
  631.         call Log(' Failed code 'gu.res'.', 1)
  632.         if def.KeepFailed then call cmd(um, 'SetType 'gu.id' F')
  633.         else call cmd(um, 'KillUrl 'hu.id)
  634.     end
  635.  
  636.     if gu.res == '0' & opts.Recursive then do
  637.         call cmd(gh, 'GetHeaderString "Content-Type:"')
  638.         if (index(upper(ghres), 'TEXT/HTML')~=0) | (index(upper(gu.path), '.HTM') > (length(gu.path)-5)) then do
  639.             if gu.depth ~= 0 then do
  640.                 if gu.depth = -1 then gu.newdepth = -1
  641.                 else gu.newdepth = gu.depth - 1
  642.  
  643.                 thecmd = def.ScanHTML' "'opts.SaveRoot||gu.path'" "'def.TempFile'"'
  644.                 thecmd = thecmd' Base "'gu.url'" Pattern2 "'def.ParsePattern'" NoF# NoQuery'
  645.                 if opts.Pattern ~= '' then thecmd = thecmd' Pattern "'opts.Pattern'"'
  646.                 if opts.NoSrc then thecmd = thecmd' NoSrc'
  647.                 if opts.NoHRef then thecmd = thecmd' NoHRef'
  648.                 if opts.NoBG then thecmd = thecmd' NoBG'
  649.  
  650.                 address command thecmd
  651.                 if RC ~= 0 then call Log ' (Can''t parse)'
  652.                 else do
  653.                     if cmd(um, 'ReadFile 'def.TempFile' Q Depth 'gu.newdepth) ~= 0 then do
  654.                         call Log ' (Can''t add urls)'
  655.                     end
  656.                     else do
  657.                         if umres = '0' then call Log ''
  658.                         else if umres = '1' then
  659.                             call Log ' (+1 url)'
  660.                         else call Log ' (+'umres' urls)'
  661.                     end
  662.                 end
  663.                 call Delete(def.TempFile)
  664.             end
  665.             else call Log
  666.         end
  667.         else call Log
  668.     end
  669.     else call Log ''
  670.  
  671.     call SecureWorkFile
  672.  
  673. return 0
  674.  
  675. novalue:
  676.     call oops("Novalue", sigl)
  677. syntax:
  678.     call oops("Syntax(RC="RC")", sigl, RC)
  679. failure:
  680.     call oops("Failure(RC="RC")", sigl)
  681. ioerr:
  682.     call oops("IOErr", sigl)
  683. halt:
  684.     call oops("Halt", sigl)
  685. error:
  686.     call oops("Error", sigl)
  687. oops:
  688.     parse arg what, badline, code
  689.     if code != '' then
  690.         call DoFail(40, "ERR: Line "badline what errortext(code))
  691.     else
  692.         call DoFail(40, "ERR: Line "badline what)
  693.  
  694.